"""
flake8 可能出现的错误类型

- Flake8 cn Docs: https://www.osgeo.cn/flake8/user/error-codes.html
- Flake8 Docs: https://flake8.pycqa.org/en/latest/user/index.html
- E、W 类错误：https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes
"""

import textwrap


class FlakeErrorBase:
    """ flake8 错误基类 """

    _reason: str = ""
    _reason_cn: str = ""
    _suggestion: str = ""
    _error_example: str = ""
    _correct_example: str = ""

    @property
    def code(self) -> str:
        """ 错误编号 """

        return self.__class__.__name__

    @property
    def reason(self) -> str:
        """ 错误原因 """

        return self.__trim_space(self._reason)

    @property
    def reason_cn(self) -> str:
        """ 错误原因（中文） """

        return self.__trim_space(self._reason_cn)

    @property
    def suggestion(self) -> str:
        """ 建议 """

        return self.__trim_space(self._suggestion)

    @property
    def error_example(self) -> str:
        """ 错误示例 代码 """

        return self.__trim_space(self._error_example)

    @property
    def correct_example(self) -> str:
        """ 正确示例 代码 """

        return self.__trim_space(self._correct_example)

    @classmethod
    def __trim_space(cls, content: str) -> str:
        """ 移除空格，并移除开头的换行 """

        if not content:
            return ""

        content: str = textwrap.dedent(content)

        if content.startswith("\n"):
            content = content.replace("\n", "", 1)

        return content


class E:
    """
    E 类错误（来自 pycodestyle 报告的错误）

    E1: Indentation 缩进
    E2: Whitespace 空格
    E3: Blank line 空行
    E4: Import 导入
    E5: Line length 行长
    E7: Statement 陈述
    E9: Runtime 运行时
    """

    class E101(FlakeErrorBase):
        _reason = "indentation contains mixed spaces and tabs"
        _reason_cn = "缩进包含混合的空格和制表符"
        _suggestion = "建议代码缩进中不要出现混合的空格和制表符，最好不要出现制表符"
        _error_example = """
        >>> if a == 1:
        >>>     if b == 2:
        >>> 	    c = 3
        """
        _correct_example = """
        >>> if a == 1:
        >>>     if b == 2:
        >>>         c = 3
        """

    class E111(FlakeErrorBase):
        _reason = "indentation is not a multiple of 4"
        _reason_cn = "缩进不是 4 的倍数"
        _suggestion = "建议代码缩进都改用 4 的倍数"
        _error_example = """
        >>> if a == 1:
        >>>  b = 2
        """
        _correct_example = """
        >>> if a == 1:
        >>>     b = 2
        """

    class E117(FlakeErrorBase):
        _reason = "over-indented"
        _reason_cn = "过度缩进"
        _suggestion = "不要出现过度缩进，1 层缩进用 4 个空格"
        _error_example = """
        >>> if a == 1:
        >>>         b = 2
        """
        _correct_example = """
        >>> if a == 1:
        >>>     b = 2
        """

    class E127(FlakeErrorBase):
        _reason = "continuation line over-indented for visual indent"
        _reason_cn = "过视觉缩进的连续行过度缩进（续行的缩进过多，导致视觉上的缩进不正确）"
        _suggestion = "参数缩进要对齐"
        _error_example = """
        >>> foo(a,
        ...     b,
        ...      c)
        """
        _correct_example = """
        >>> foo(a,
        ...     b,
        ...      c)

        >>> foo(
        ...     a,
        ...     b,
        ...     c,
        ... )
        """

    class E128(FlakeErrorBase):
        _reason = "continuation line under-indented for visual indent"
        _reason_cn = "视觉缩进的连续行缩进不足（续行的缩进过少，导致视觉上的缩进不正确）"
        _suggestion = "参数缩进要对齐"
        _error_example = """
        >>> foo(a,
        ...     b,
        ...    c)
        """
        _correct_example = """
        >>> foo(a,
        ...     b,
        ...      c)

        >>> foo(
        ...     a,
        ...     b,
        ...     c,
        ... )
        """

    class E501(FlakeErrorBase):
        _reason = "line too long (89 > 79 characters)"
        _reason_cn = "行过长，超过了 79 个字符"
        _suggestion = "建议单行不超过 79 个字符，或者把该限制调大 `max-line-length = 120`"
        _error_example = """
        >>> from typing import *
        """
        _correct_example = """
        >>> from typing import (
        ...     List,
        ...     Union,
        ... )
        """


class F:
    """ F 类错误（来自 pyflakes 报告的错误） """

    class F401(FlakeErrorBase):
        _reason = "'module' imported but unused"
        _reason_cn = "模块导入了，但没有使用"
        _suggestion = """
        1 如果确实是导入了，未使用：
            直接移除

        2 如果导入是用于执行导入文件的定格代码:
            请在行尾加上 `# noqa: F401`

        3 如果是在 __init__.py 文件中：
            在文件开头加上 `# flake8: noqa`
        """

    class F403(FlakeErrorBase):
        _reason = "'from typing import *' used; unable to detect undefined names"
        _reason_cn = "使用了 'from typing import *'，无法检测到未定义的名称"
        _suggestion = """推荐使用明确的导入（需要什么，导入什么，而不是全部导入）"""
        _error_example = """
        >>> from typing import *
        """
        _correct_example = """
        >>> from typing import (
        >>>     List,
        >>>     Union,
        >>> )
        """

    class F405(FlakeErrorBase):
        _reason = "'List' may be undefined, or defined from star imports: typing"
        _reason_cn = "List 可能是未定义的，或者是从 typing 导入的 *"
        _suggestion = "推荐使用明确的导入（需要什么，导入什么，而不是全部导入）"
        _error_example = """
        >>> from typing import *
        >>>
        >>> List[int] nums = [1, 2, 3]
        """
        _correct_example = """
        >>> from typing import List
        >>>
        >>> List[int] nums = [1, 2, 3]
        """

    class F841(FlakeErrorBase):
        _reason = "local variable 'data' is assigned to but never used"
        _reason_cn = "局部变量定义了，但没有使用"
        _suggestion = "不使用的局部变量，直接移除"
        _error_example = """
        >>> def foo():
        >>>     data = 1
        >>>     return True
        """
        _correct_example = """
        >>> def foo():
        >>>     return True
        """


class W:
    """
    W 类错误（来自 pycodestyle 的警告）

    W1: Indentation warning 缩进警告
    W2: Whitespace warning 空格警告
    W3: Blank line warning 空行警告
    W5: Line break warning 换行警告
    W6: Deprecation warning 弃用警告
    """

    class W191(FlakeErrorBase):
        _reason = "indentation contains tabs"
        _reason_cn = "缩进包含了制表符"
        _suggestion = "单次缩进使用 4 个空格"
        _error_example = """
        >>> if a == 1:
        >>> 	b = 2
        """
        _correct_example = """
        >>> if a == 1:
        >>>     b = 2
        """

    class W292(FlakeErrorBase):
        _reason = "no newline at end of file"
        _reason_cn = "文件末尾没有换行"
        _suggestion = "每个 `xxx.py` 末尾要添加一个空行"
        _error_example = """
        - test.py
        >>> a = 1
        >>> b = 2
        """
        _correct_example = """
        - test.py
        >>> a = 1
        >>> b = 2
        >>> 
        """

    class W293(FlakeErrorBase):
        _reason = "blank line contains whitespace"
        _reason_cn = "空行包含了空格"
        _suggestion = "空行就是单独的空行，不要有空格"
        _error_example = """
        >>> a = 1
        >>>       
        >>> b = 2
        """
        _correct_example = """
        >>> a = 1
        >>> 
        >>> b = 2
        """

    class W503(FlakeErrorBase):
        _reason = "line break before binary operator"
        _reason_cn = "二元操作符之前出现了换行"
        _suggestion = "忽略该错误"
        _error_example = """
        >>> if (
        ...     a < 1
        ...     and b > 1
        ... ):
        """
        _correct_example = """
        >>> if (
        ...     a < 1
        ...     and b > 1
        ... ):
        """

    class W504(FlakeErrorBase):
        _reason = "line break after binary operator"
        _reason_cn = "二元操作符之后出现了换行"
        _suggestion = "换行放到二元操作符之前，参考 W503"
        _error_example = """
        >>> if (
        ...     a < 1 and
        ...     b > 1
        ... ):
        """
        _correct_example = """
        >>> if (
        ...     a < 1
        ...     and b > 1
        ... ):
        """
